package com.example.neuronview

import java.io.File
import java.io.InputStream
import kotlin.compareTo
import glm_.vec3.Vec3
import glm_.vec2.Vec2

data class Face(val vertexIndices:List<Int>, val textureCoordinates: List<Int>?, val normals: List<Int>?)
data class Mesh(var vertices : List<Vec3>, var normals:List<Vec3>, var faces:List<Face>, val minVertex: Vec3, val maxVertex: Vec3)

fun Mesh.toFloatArray(): FloatArray {
    // 每个顶点包含的组件数：3个位置坐标 + 2个纹理坐标 + 3个法线坐标
    val componentsPerVertex = 3+3
    val floatArray = FloatArray(faces.sumOf { it.vertexIndices.size * componentsPerVertex })
    var floatIndex = 0

    faces.forEach { face ->
        face.vertexIndices.forEachIndexed { index, vertexIndex ->
            // 添加顶点位置
            val vertex = vertices[vertexIndex]
            val scaleVertex = Vec3(vertex.x/10000.0f,vertex.y/10000.0f,vertex.z/10000.0f)
            floatArray[floatIndex++] = scaleVertex.x
            floatArray[floatIndex++] = scaleVertex.y
            floatArray[floatIndex++] = scaleVertex.z

//            // 添加纹理坐标（如果有）
//            face.textureCoordinates?.get(index)?.let { texCoordIndex ->
//                val texCoord = textureCoordinates[texCoordIndex]
//                floatArray[floatIndex++] = texCoord.u
//                floatArray[floatIndex++] = texCoord.v
//            } ?: run {
//                // 如果没有纹理坐标，填充默认值
//                floatArray[floatIndex++] = 0f
//                floatArray[floatIndex++] = 0f
//            }
//
            // 添加法线（如果有）
            face.normals?.get(index)?.let { normalIndex ->
                val normal = normals[normalIndex]
                floatArray[floatIndex++] = normal.x
                floatArray[floatIndex++] = normal.y
                floatArray[floatIndex++] = normal.z
            } ?: run {
                // 如果没有法线，填充默认值
                floatArray[floatIndex++] = 0f
                floatArray[floatIndex++] = 0f
                floatArray[floatIndex++] = 1f
            }
        }
    }

    return floatArray
}
fun parseObjStream(stream: InputStream):Mesh{
    val faces = mutableListOf<Face>()
    val vertices = mutableListOf<Vec3>()
    val textureCoordinates = mutableListOf<Vec2>()
    val normals = mutableListOf<Vec3>()

    val minVertex:Vec3=Vec3(9999.0f,9999.0f,9999.0f)
    val maxVertex:Vec3=Vec3(-9999.0f,-9999.0f,-9999.0f)
    val content = stream.bufferedReader().use{it.readLines()}
    content.forEach {  line->
        val parts = line.split("\\s+".toRegex())
        when (parts[0]) {
            "v" -> {
                val vertex = Vec3(parts[1].toFloat(), parts[2].toFloat(), parts[3].toFloat())
                vertices.add(vertex)
                minVertex.x=if (minVertex.x>vertex.x) vertex.x else minVertex.x
                minVertex.y=if (minVertex.y>vertex.y) vertex.y else minVertex.y
                minVertex.z=if (minVertex.z>vertex.z) vertex.z else minVertex.z
                maxVertex.x=if (maxVertex.x<vertex.x) vertex.x else maxVertex.x
                maxVertex.y=if (maxVertex.y<vertex.y) vertex.y else maxVertex.y
                maxVertex.z=if (maxVertex.z<vertex.z) vertex.z else maxVertex.z
            }
            "vt" -> textureCoordinates.add(Vec2(parts[1].toFloat(), parts[2].toFloat()))
            "vn" -> normals.add(Vec3(parts[1].toFloat(), parts[2].toFloat(), parts[3].toFloat()))
            "f" -> {
                val vertexIndices = mutableListOf<Int>()
                val textureCoordIndices = mutableListOf<Int>()
                val normalIndices = mutableListOf<Int>()
//                println(parts)
                for (i in 1 until parts.size) {
                    val indices = parts[i].split("//")
                    if (indices[0]!="")  vertexIndices.add(indices[0].toInt() - 1) // OBJ files are 1-indexed, convert to 0-indexing for Kotlin lists
                    if (indices.size > 1 && indices[1].isNotEmpty()) normalIndices.add(indices[1].toInt() - 1)
                    if (indices.size > 2 && indices[2].isNotEmpty()) textureCoordIndices.add(indices[2].toInt() - 1)
                }
                faces.add(Face( vertexIndices, if (textureCoordIndices.isEmpty()) null else textureCoordIndices, if (normalIndices.isEmpty()) null else normalIndices))
            }
        }
    }
    return Mesh(vertices,normals,faces,minVertex,maxVertex);

}
fun parseObjFile(filePath: String): Mesh {
    val faces = mutableListOf<Face>()
    val vertices = mutableListOf<Vec3>()
    val textureCoordinates = mutableListOf<Vec2>()
    val normals = mutableListOf<Vec3>()
    val minVertex:Vec3=Vec3(9999.0f,9999.0f,9999.0f)
    val maxVertex:Vec3=Vec3(-9999.0f,-9999.0f,-9999.0f)

    File(filePath).forEachLine { line ->
        val parts = line.split("\\s+".toRegex())
        when (parts[0]) {
            "v" -> {
                val vertex = Vec3(parts[1].toFloat(), parts[2].toFloat(), parts[3].toFloat())
                vertices.add(vertex)
                minVertex.x=if (minVertex.x>vertex.x) vertex.x else minVertex.x
                minVertex.y=if (minVertex.y>vertex.y) vertex.y else minVertex.y
                minVertex.z=if (minVertex.z>vertex.z) vertex.z else minVertex.z
                maxVertex.x=if (maxVertex.x<vertex.x) vertex.x else maxVertex.x
                maxVertex.y=if (maxVertex.y<vertex.y) vertex.y else maxVertex.y
                maxVertex.z=if (maxVertex.z<vertex.z) vertex.z else maxVertex.z
            }
            "vt" -> textureCoordinates.add(Vec2(parts[1].toFloat(), parts[2].toFloat()))
            "vn" -> normals.add(Vec3(parts[1].toFloat(), parts[2].toFloat(), parts[3].toFloat()))
            "f" -> {
                val vertexIndices = mutableListOf<Int>()
                val textureCoordIndices = mutableListOf<Int>()
                val normalIndices = mutableListOf<Int>()
                for (i in 1 until parts.size) {
                    val indices = parts[i].split("/")
                    vertexIndices.add(indices[0].toInt() - 1) // OBJ files are 1-indexed, convert to 0-indexing for Kotlin lists
                    if (indices.size > 1 && indices[1].isNotEmpty()) textureCoordIndices.add(indices[1].toInt() - 1)
                    if (indices.size > 2 && indices[2].isNotEmpty()) normalIndices.add(indices[2].toInt() - 1)
                }
                faces.add(Face(vertexIndices, if (textureCoordIndices.isEmpty()) null else textureCoordIndices, if (normalIndices.isEmpty()) null else normalIndices))
            }
        }
    }
    return Mesh(vertices,normals,faces,minVertex,maxVertex)
}
